package top.eleven.sixpence.generaterollbacksql.convertor;

import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.eleven.sixpence.generaterollbacksql.annotation.Convertor;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Set;

/**
 * convertor 管理类
 *
 * @author eleven
 */
public class ConvertorManager {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConvertorManager.class);

    private final HashMap<String, Object> convertors = new HashMap<>();

    private ConvertorManager() {
        init();
    }

    public static ConvertorManager build() {
        return ConvertorManagerFactory.NEW_INSTANCE;
    }

    public HashMap<String, Object> getConvertors() {
        return convertors;
    }

    private void init(){
        init(BaseConvertor.class);
    }

    private <T> void init(Class<T> clazz){
        // 获取所有Convertor 并加载进map中
        Set<Class<? extends T>> classes = getSubClasses(clazz);
        for (Class<? extends T> subClass : classes) {
            if (subClass.isInterface() || Modifier.isAbstract(subClass.getModifiers())) {
                init(subClass);
                continue;
            };
            try {
                Convertor annotation = subClass.getAnnotation(Convertor.class);
                String[] prefix = annotation.sqlPrefix();
                Constructor<? extends T> constructor = subClass.getConstructor();
                T value = constructor.newInstance();
                for (int i = 0; i < prefix.length; i++) {
                    convertors.put(prefix[i], value);
                }
            } catch (Exception e) {
                LOGGER.error("init convertor failed!");
                LOGGER.error(String.format("create bean %s failed", subClass.getName()));
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 获取指定类的的所有实现类
     *
     * @param clazz
     * @return
     * @param <T>
     */
    public <T> Set<Class<? extends T>> getSubClasses(Class<T> clazz) {
        Reflections reflections = new Reflections("top.eleven.sixpence");
        return reflections.getSubTypesOf(clazz);
    }

    private static final class ConvertorManagerFactory {
        private static final  ConvertorManager NEW_INSTANCE = new ConvertorManager();
    }

}
